package com.example.mybatisplusdemo.service.combination;

import com.example.mybatisplusdemo.model.domain.Flight;
import com.example.mybatisplusdemo.model.domain.ItineraryRequest;
import com.example.mybatisplusdemo.model.dto.SmartCombinationDTO;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class FlightCombinationService {

    public List<SmartCombinationDTO> findSmartCombinations(
            List<Flight> flights,
            ItineraryRequest request
    ) {
        // 1. 按航空公司分组
        Map<String, List<Flight>> byAirline = flights.stream()
                .collect(Collectors.groupingBy(Flight::getAirlineCode));

        // 2. 生成所有可能的双航班组合
        List<List<Flight>> combinations = new ArrayList<>();
        for (Flight f1 : flights) {
            byAirline.getOrDefault(f1.getAirlineCode(), Collections.emptyList())
                    .stream()
                    .filter(f2 -> isValidConnection(f1, f2))
                    .map(f2 -> Arrays.asList(f1, f2))
                    .forEach(combinations::add);
        }

        // 3. 转换为DTO并计算属性
        return combinations.stream()
                .map(this::createCombinationDTO)
                .sorted(Comparator.comparing(SmartCombinationDTO::getRecommendationScore).reversed())
                .limit(5) // 返回前5个最佳组合
                .collect(Collectors.toList());
    }

    private boolean isValidConnection(Flight first, Flight second) {
        // 中转时间在90-240分钟之间
        Duration transferTime = Duration.between(
                first.getArrivalTime(),
                second.getDepartureTime()
        );
        return !transferTime.isNegative() &&
                transferTime.toMinutes() >= 90 &&
                transferTime.toMinutes() <= 240;
    }

    private SmartCombinationDTO createCombinationDTO(List<Flight> combo) {
        SmartCombinationDTO dto = new SmartCombinationDTO();
        dto.setFlights(combo);
        dto.setTotalPrice(calculateTotalPrice(combo).doubleValue());
        dto.setTotalDuration(calculateTotalDuration(combo));
        dto.setAdvantages(detectAdvantages(combo));
        dto.setRecommendationScore(calculateRecommendationScore(combo));
        return dto;
    }

    private BigDecimal calculateTotalPrice(List<Flight> combo) {
        return combo.stream()
                .map(Flight::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    private int calculateTotalDuration(List<Flight> combo) {
        if (combo == null || combo.isEmpty()) return 0;

        // 计算飞行总时长
        long flightMinutes = combo.stream()
                .mapToLong(f -> Duration.between(
                        f.getDepartureTime(),
                        f.getArrivalTime()
                ).toMinutes())
                .sum();

        // 计算中转时间（如果是组合航班）
        long transferMinutes = 0;
        if (combo.size() > 1) {
            for (int i = 0; i < combo.size() - 1; i++) {
                transferMinutes += Duration.between(
                        combo.get(i).getArrivalTime(),
                        combo.get(i + 1).getDepartureTime()
                ).toMinutes();
            }
        }

        return (int)(flightMinutes + transferMinutes);
    }

    private String detectAdvantages(List<Flight> combo) {
        StringBuilder advantages = new StringBuilder();

        // 1. 同航空公司优势
        if (combo.stream().map(Flight::getAirlineCode).distinct().count() == 1) {
            advantages.append("同航司中转|行李直挂|");
        }

        // 2. 中转时间优势
        if (combo.size() > 1) {
            long transferTime = Duration.between(
                    combo.get(0).getArrivalTime(),
                    combo.get(1).getDepartureTime()
            ).toMinutes();

            if (transferTime >= 90 && transferTime <= 180) {
                advantages.append("理想中转时间|");
            }
        }

        // 3. 价格优势
        BigDecimal totalPrice = calculateTotalPrice(combo);
        BigDecimal avgPrice = totalPrice.divide(BigDecimal.valueOf(combo.size()), 2, BigDecimal.ROUND_HALF_UP);
        if (avgPrice.compareTo(BigDecimal.valueOf(1000)) < 0) {
            advantages.append("超值组合|");
        }

        // 4. 准点率优势
        double avgPunctuality = combo.stream()
                .mapToDouble(f -> f.getPunctualityRate().doubleValue())
                .average()
                .orElse(0);
        if (avgPunctuality > 0.9) {
            advantages.append("高准点率|");
        }

        return advantages.length() > 0 ?
                advantages.substring(0, advantages.length() - 1) :
                "标准组合";
    }

    private double calculateRecommendationScore(List<Flight> combo) {
        // 1. 价格得分（越低越好）
        double priceScore = 1 - (calculateTotalPrice(combo).doubleValue() / 10000);

        // 2. 准点率得分
        double punctualityScore = combo.stream()
                .mapToDouble(f -> f.getPunctualityRate().doubleValue())
                .average()
                .orElse(0);

        // 3. 舒适度得分
        double comfortScore = combo.stream()
                .mapToDouble(f -> f.getSeatComfort().doubleValue())
                .average()
                .orElse(0);

        // 4. 碳排放得分（越低越好）
        double carbonScore = 1 - (combo.stream()
                .mapToDouble(f -> f.getCarbonEmission().doubleValue())
                .sum() / 1000);

        // 5. 中转便利性得分
        double transferScore = calculateTransferScore(combo);

        // 综合评分（权重可调整）
        return priceScore * 0.3 +
                punctualityScore * 0.25 +
                comfortScore * 0.2 +
                carbonScore * 0.15 +
                transferScore * 0.1;
    }

    private double calculateTransferScore(List<Flight> combo) {
        if (combo.size() <= 1) return 1.0; // 直飞航班满分

        // 1. 中转时间得分（90-180分钟为最佳）
        long transferTime = Duration.between(
                combo.get(0).getArrivalTime(),
                combo.get(1).getDepartureTime()
        ).toMinutes();

        double timeScore;
        if (transferTime >= 90 && transferTime <= 180) {
            timeScore = 1.0;
        } else if (transferTime < 90) {
            timeScore = 0.5 - (90 - transferTime) / 180.0;
        } else {
            timeScore = 0.8 - (transferTime - 180) / 600.0;
        }

        // 2. 同航司加分
        double airlineScore = combo.get(0).getAirlineCode().equals(combo.get(1).getAirlineCode()) ? 0.5 : 0;

        return Math.min(1.0, Math.max(0, timeScore + airlineScore));
    }
}